package com.blacktry.GATest;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.blacktry.entity.model.Classroom;
import com.blacktry.entity.model.Course;
import com.blacktry.entity.model.Vo.ClassCourseVo;
import com.blacktry.entity.model.Vo.Courseinformation2;
import com.blacktry.entity.model.Vo.UserVo;
import com.blacktry.service.*;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

//@RunWith(SpringRunner.class)
@SpringBootTest
public class TimetableGA {
    // 已验
    @Test
    public void test() {
        Timetable timetable = initializeTimetable();
        // 种群100 变异率0.01 交叉率0.9 2个精英个体 锦标赛规模5
        GeneticAlgorithm ga = new GeneticAlgorithm(100, 0.01, 0.9, 2, 5);

        Population population = ga.initPopulation(timetable);

        ga.evalPopulation(population, timetable);

        int generation = 1;

        while (ga.isTerminationConditionMet(generation, 1000) == false
                && ga.isTerminationConditionMet(population) == false) {

            System.out.println("G" + generation + " Best fitness: " + population.getFittest(0).getFitness());

            population = ga.crossoverPopulation(population);

            population = ga.mutatePopulation(population, timetable);

            ga.evalPopulation(population, timetable);
            generation++;

//            ga.coolTemperature();
        }
        timetable.createClasses(population.getFittest(0));
        System.out.println();
        System.out.println("Solution found in " + generation + " generations");
        System.out.println("Final solution fitness: " + population.getFittest(0).getFitness());
        System.out.println("Clashes: " + timetable.calcClashes());


        System.out.println();
        Class classes[] = timetable.getClasses();
        int classIndex = 1;
        for (Class bestClass : classes) {
            System.out.println("Class " + classIndex + ":");
            System.out.println("Module: " +
                    timetable.getModule(bestClass.getModuleId()).getModuleName() + "    || id->:" + bestClass.getModuleId());
            System.out.println("Group: " +
                    timetable.getGroup(bestClass.getGroupId()).getGroupId() + "    || id->:" + bestClass.getGroupId());
            System.out.println("Room: " +
                    timetable.getRoom(bestClass.getRoomId()).getRoomNumber() + "    || id->:" + bestClass.getRoomId());
            System.out.println("Professor: " +
                    timetable.getProfessor(bestClass.getProfessorId()).getProfessorName() + "    || id->:" + bestClass.getProfessorId());
            System.out.println("Time: " +
                    timetable.getTimeslot(bestClass.getTimeslotId()).getTimeslot() + "    || id->:" + bestClass.getTimeslotId());
            System.out.println("-----");
            classIndex++;
        }
        System.out.println();
        System.out.println("Solution found in " + generation + " generations");
        System.out.println("Final solution fitness: " + population.getFittest(0).getFitness());
        System.out.println("Clashes: " + timetable.calcClashes());

    }

    @Test
    public void printTest() {
        // 班级表：id主键,Size班级容量大小，new int 里面为改班级要修的课程
        for (ClassCourseVo classCourseVo : courseDistributionService.selectClassId2Course()) {
            // classId=null
            if(null!=classCourseVo.getClassId()){
                System.out.println(classCourseVo.getClassId());
                System.out.println(splitForSum(classCourseVo.getClassId()));
                System.out.println(Arrays.toString(classCourseVo.getCourseIds().stream().mapToLong(Long::valueOf).toArray()));
            }

        }

    }

    public long splitForSum(String str) {
        long sum = 0;
        String[] split = str.split("\\(|\\)");
        for (int i = 1; i < split.length; i+=2) {
            sum += Long.valueOf(split[i]);

        }
        return sum;
    }

    @Autowired
    private CourseDistributionService courseDistributionService;

    @Autowired
    private CourseInfoService courseInfoService;

    @Autowired
    private CourseService courseService;

    @Autowired
    private ClassroomService classroomService;

    @Autowired
    private AdminService adminService;

    private Timetable initializeTimetable() {
        Timetable timetable = new Timetable();

        List<Classroom> list = classroomService.list();
        for (Classroom classroom : list) {
            // 教室表: id主键 name教室名 capacity容纳人数
            timetable.addRoom(classroom.getId(), classroom.getName(), classroom.getNum());
        }

        // 上课时间段安排表 id主键,timeslot时间段
        // 周一
        timetable.addTimeslot(11, "Mon 8:00 - 9:40 ");
        timetable.addTimeslot(12, "Mon 10:00 - 11:40");
        timetable.addTimeslot(13, "Mon 14:30 - 16:10");
        timetable.addTimeslot(14, "Mon 16:20 - 18:00");
        timetable.addTimeslot(15, "Mon 19:00 - 20:30");
        // 周二
        timetable.addTimeslot(21, "Tue 8:00 - 9:40 ");
        timetable.addTimeslot(22, "Tue 10:00 - 11:40");
        timetable.addTimeslot(23, "Tue 14:30 - 16:10");
        timetable.addTimeslot(24, "Tue 16:20 - 18:00");
        timetable.addTimeslot(25, "Tue 19:00 - 20:30");
        // 周三
        timetable.addTimeslot(31, "Wed 8:00 - 9:40 ");
        timetable.addTimeslot(32, "Wed 10:00 - 11:40");
        timetable.addTimeslot(33, "Wed 14:30 - 16:10");
        timetable.addTimeslot(34, "Wed 16:20 - 18:00");
        timetable.addTimeslot(35, "Wed 19:00 - 20:30");
        // 周四
        timetable.addTimeslot(41, "Thu 8:00 - 9:40 ");
        timetable.addTimeslot(42, "Thu 10:00 - 11:40");
        timetable.addTimeslot(43, "Thu 14:30 - 16:10");
        timetable.addTimeslot(44, "Thu 16:20 - 18:00");
        timetable.addTimeslot(45, "Thu 19:00 - 20:30");
        // 周五
        timetable.addTimeslot(51, "Fri 8:00 - 9:40 ");
        timetable.addTimeslot(52, "Fri 10:00 - 11:40");
        timetable.addTimeslot(53, "Fri 14:30 - 16:10");
        timetable.addTimeslot(54, "Fri 16:20 - 18:00");
        timetable.addTimeslot(55, "Fri 19:00 - 20:30");


        // 教师表:id主键,Name名字
        Page<UserVo> userVoPage = adminService.selectRole("教师", new Page<>(1, 999));
        for (UserVo teacher : userVoPage.getRecords()) {
            System.out.println(teacher);
            timetable.addProfessor(Long.parseLong(teacher.getUsername()), teacher.getName());
        }

        // 课程表：id主键,Code课程码,module课程名,int[]该课能被那些老师id教授
        List<Course> select = courseService.list();
        for (Course course : select) {
            // 所有课程
            if (!course.getCourseId().isEmpty()) {
                List<Long> teachers = new ArrayList<>();
                // 某个课程的所有授课老师
                Page<Courseinformation2> courseinformation2Page = courseInfoService.selectUser(course.getCourseId(), new Page<>(1, 99));
                if (courseinformation2Page.getRecords().size() != 0) {
                    List<UserVo> userList = courseinformation2Page.getRecords().get(0).getUserList();
                    for (UserVo userVo : userList) {
                        teachers.add(Long.valueOf(userVo.getUsername()));
                    }
                    timetable.addModule(course.getId(), course.getCourseId(), course.getCourseName(), teachers.stream().mapToLong(Long::valueOf).toArray());
                }

            }
        }

        // 班级表：id主键,Size班级容量大小，new int 里面为改班级要修的课程
        for (ClassCourseVo classCourseVo : courseDistributionService.selectClassId2Course()) {
            // classId=null
            if(null!=classCourseVo.getClassId()){
                System.out.println(classCourseVo.getClassId());
                System.out.println(splitForSum(classCourseVo.getClassId()));
                System.out.println(Arrays.toString(classCourseVo.getCourseIds().stream().mapToLong(Long::valueOf).toArray()));
//                timetable.addGroup(1, 10, new long[]{764});
            }

        }

//        timetable.addGroup(1, 10, new long[]{764});
        return timetable;
    }

}
